home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / msjv6-5.zip / WINDOS.ZIP / WINHEAP.C < prev    next >
C/C++ Source or Header  |  1991-09-01  |  11KB  |  408 lines

  1. /*
  2. WINHEAP.C -- Heap routines for Microsoft Windows
  3.     _amblksiz
  4.     _fmalloc, _fcalloc, _fexpand, _frealloc, _ffree, _fmsize
  5.     _nmalloc, _ncalloc, _nexpand, _nrealloc, _nfree, _nmsize
  6.     _malloc,  _calloc,  _expand,  _realloc,  _free,  _msize
  7.         
  8. from Microsoft Systems Journal, September 1991
  9. Andrew Schulman (andrew@pharlap.com)
  10. */
  11.  
  12. #include <windows.h>
  13. #include <memory.h>
  14. #include <stdlib.h>
  15. #ifdef __BORLANDC__
  16. #include "based.h"
  17. #else
  18. #include <malloc.h>
  19. #endif
  20. #include "winio.h"
  21.  
  22. #ifdef __BORLANDC__
  23. void _ffree(void _far *fp);
  24. size_t _fmsize(void _far *memblock);
  25. void _nfree(void _near *memblock);
  26. size_t _nmsize(void _near *memblock);
  27. #endif
  28.  
  29. #define MAKEP(seg,ofs)  \
  30.     ((void _far *)(((DWORD)(seg) << 16) | (unsigned) (ofs)))
  31.  
  32. #define SELECTOROF(fp)      ((WORD)(((DWORD)(fp)) >> 16))
  33.  
  34. #define OFFSETOF(fp)        ((WORD)(DWORD)(fp))
  35.     
  36. #define MAX_SEL             1024    /* enough for 64 megabytes */
  37.  
  38. typedef struct {
  39.     WORD sel;
  40.     WORD items;
  41.     WORD failsize;
  42.     } MEMHEAP;
  43.     
  44. static MEMHEAP _near *memheap = 0;
  45. static int numheaps = 0;
  46.  
  47. /* for stats */
  48. static unsigned long num_try_allocs = 0L;
  49. static unsigned long num_bmallocs = 0L;
  50. static unsigned long num_try_frees = 0L;
  51. static unsigned long num_fmalloc = 0L;
  52. static unsigned long num_frealloc = 0L;
  53. static unsigned long num_ffree = 0L;
  54. static unsigned long num_get_pheap_loops = 0L;
  55.  
  56. static MEMHEAP _near *add_heap(unsigned initial_size);
  57. static BOOL memheap_init(void);
  58. static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size);
  59. static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs);
  60. static MEMHEAP _near *get_pheap(unsigned sel);
  61. static BOOL malloc_fail(unsigned size);
  62.  
  63. /**********************************************************************/
  64.  
  65. unsigned _near _cdecl _amblksiz = 4096;
  66.  
  67. void _far *_fmalloc(unsigned size)
  68. {
  69.     void _far *ret;
  70.     static MEMHEAP _near *pheap = 0;
  71.     MEMHEAP _near *skip;
  72.     int i;
  73.     
  74. retry:  
  75.     
  76.     num_fmalloc++;
  77.     
  78.     if (! memheap)     /* one-time initialization */
  79.         if (! memheap_init())
  80.         {
  81.             if (malloc_fail(size))
  82.                 return NULL;
  83.             else
  84.                 goto retry;
  85.         }
  86.  
  87.     /* special case for large (32k+) blocks */
  88.     if (size > (WORD) (32 << 10))
  89.     {
  90.         HANDLE h;
  91.         h = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT, 
  92.             size);
  93.         if (h)
  94.             return GlobalLock(h);
  95.         else if (malloc_fail(size))
  96.             return NULL;
  97.         else
  98.             goto retry;
  99.     }
  100.     
  101.     /* try most recently used pheap first: not surprisingly, this
  102.        dramatically improves performance */
  103.     if (! pheap) pheap = memheap;
  104.     if ((ret = try_alloc(pheap, size)) != NULL)
  105.         return ret;
  106.     else
  107.         skip = pheap;   /* don't check this one again */
  108.  
  109.     /* try to find a heap from which to allocate block */
  110.     for (i=numheaps, pheap=memheap; i--; pheap++)
  111.         if (pheap != skip)  /* don't retry one we tried already */
  112.             if ((ret = try_alloc(pheap, size)) != NULL)  /* first fit */
  113.                 return ret;
  114.             
  115.     /* still here: need to allocate a new heap and try once more */
  116.     if ((pheap = add_heap(max(size, _amblksiz))) != NULL)
  117.         if ((ret = try_alloc(pheap, size)) != NULL)
  118.             return ret;
  119.         
  120.     /* still here: memory totally exhausted */
  121.     if (malloc_fail(size))
  122.         return NULL;
  123.     else
  124.         goto retry;
  125. }
  126.  
  127. void _far *_fcalloc(unsigned num, unsigned size)
  128. {
  129.     return _fmalloc(num * size);
  130. }
  131.  
  132. void _far *_fexpand(void _far *memblock, size_t size)
  133. {
  134.     NPSTR np;
  135.     WORD old_size;
  136.     WORD sel = SELECTOROF(memblock);
  137.     WORD ofs = OFFSETOF(memblock);
  138.     
  139.     if (ofs == 0)
  140.     {
  141.         HANDLE h = GlobalHandle(sel);
  142.         if (GlobalReAlloc(h, 
  143.             GMEM_FIXED | GMEM_NODISCARD | GMEM_ZEROINIT, size) == NULL)
  144.                 return NULL;
  145.         else
  146.             return memblock;
  147.     }
  148.     
  149.     old_size = _bmsize(sel, ofs);
  150.     if (np = (NPSTR) _bexpand(sel, ofs, size))
  151.     {
  152.         MEMHEAP _near *pheap = get_pheap(sel);
  153.         return MAKEP(sel, np);
  154.     }
  155.     else
  156.         return NULL;
  157. }
  158.  
  159. void _far *_frealloc(void _far *memblock, unsigned size)
  160. {
  161.     void _far *fp;
  162.     
  163.     num_frealloc++;
  164.     
  165.     if (OFFSETOF(memblock) == 0)
  166.     {
  167.         HANDLE h = GlobalHandle(SELECTOROF(memblock));
  168.         GlobalUnlock(h);
  169.         if (GlobalReAlloc(h, 
  170.             GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT, size) == NULL)
  171.                 return NULL;
  172.         else
  173.             return GlobalLock(h);
  174.     }
  175.     
  176.     /* first try to expand the block in place */
  177.     if ((fp = _fexpand(memblock, size)) != NULL)
  178.         return fp;
  179.     else if (fp = _fmalloc(size))
  180.     {
  181.         WORD old_size = _fmsize(memblock);
  182.         _fmemcpy(fp, memblock, min(old_size, size));
  183.         _ffree(memblock);
  184.         return fp;
  185.     }
  186.     else
  187.         return NULL;
  188. }
  189.  
  190. void _ffree(void _far *fp)
  191. {
  192.     WORD sel, ofs;
  193.     MEMHEAP _near *pheap;
  194.     
  195.     num_ffree++;
  196.     
  197.     if (fp == NULL)
  198.         return;
  199.  
  200.     sel = SELECTOROF(fp);
  201.     ofs = OFFSETOF(fp);
  202.     
  203.     /* special case for (large) global blocks */
  204.     if (ofs == 0)
  205.     {
  206.         HANDLE h = GlobalHandle(sel);
  207.         GlobalUnlock(h);
  208.         GlobalFree(h);
  209.         return;
  210.     }
  211.     
  212.     if ((pheap = get_pheap(sel)) != NULL)
  213.         try_free(pheap, sel, ofs);
  214. }
  215.  
  216. size_t _fmsize(void _far *memblock)
  217. {
  218.     unsigned sel = SELECTOROF(memblock);
  219.     unsigned ofs = OFFSETOF(memblock);
  220.     return ofs? _bmsize(sel, ofs) : GlobalSize(GlobalHandle(sel));
  221. }
  222.  
  223. /**********************************************************************/
  224.  
  225. static BOOL memheap_init(void)
  226. {
  227.     HANDLE h;
  228.     
  229.     h = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, MAX_SEL * sizeof(MEMHEAP));
  230.     if (h == NULL)
  231.         return FALSE;
  232.     if ((memheap = (MEMHEAP _near *) LocalLock(h)) == NULL)
  233.         return FALSE;
  234.     if (add_heap(_amblksiz) == NULL)
  235.         return FALSE;
  236.     return TRUE;
  237. }
  238.  
  239. static MEMHEAP _near *get_pheap(unsigned sel)
  240. {
  241.     static MEMHEAP _near *pheap = (MEMHEAP _near *) 0;
  242.     int i;
  243.     if (! pheap) 
  244.         pheap = memheap;
  245.     if (pheap->sel == sel) 
  246.         return pheap;
  247.     num_get_pheap_loops++;
  248.     for (i=numheaps, pheap=memheap; i--; pheap++)
  249.         if (pheap->sel == sel)
  250.             return pheap;
  251.     /* still here */
  252.     return NULL;
  253. }
  254.     
  255. static MEMHEAP _near *add_heap(unsigned initial_size)
  256. {
  257.     WORD sel;
  258.     MEMHEAP _near *pheap;
  259.     int i;
  260.     
  261.     if ((sel = _bheapseg(initial_size)) == (WORD) -1)
  262.         return NULL;
  263.     
  264.     /* find first free space in memheap array */
  265.     for (i=0, pheap=memheap; i<numheaps; i++, pheap++)
  266.         if (pheap->sel == 0)
  267.             break;
  268.     if (i==numheaps) 
  269.         numheaps++;
  270.     
  271.     pheap->sel = sel;
  272.     pheap->items = 0;
  273.     pheap->failsize = 0xFFFFU;
  274.     
  275.     return pheap;
  276. }
  277.  
  278. static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size)
  279. {
  280.     NPSTR np;
  281.     num_try_allocs++;
  282.     if (pheap->sel && (pheap->failsize > size))
  283.     {
  284.         num_bmallocs++;
  285.         if ((np = (NPSTR) _bmalloc(pheap->sel, size)) != NULL)
  286.         {
  287.             pheap->items++;
  288.             return MAKEP(pheap->sel, np);
  289.         }
  290.         else
  291.             pheap->failsize = size;
  292.     }
  293.     return NULL;
  294. }
  295.         
  296. static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs)
  297. {
  298.     WORD size;
  299.     
  300.  
  301.     num_try_frees++;
  302.     
  303.     if (pheap->sel != sel)
  304.         return FALSE;
  305.  
  306.     size = _bmsize(sel, ofs);
  307.     _bfree(sel, (NPSTR) ofs);
  308.     pheap->failsize += size; // rough estimate okay
  309.     pheap->items--;
  310.     if (pheap->items == 0)   // return empties to Windows
  311.     {
  312.         if (_bfreeseg(pheap->sel) == 0)
  313.         {
  314.             pheap->sel = 0;
  315.             return TRUE;
  316.         }
  317.         else
  318.             return FALSE;
  319.     }
  320.     return TRUE;
  321. }
  322.  
  323. /**********************************************************************/
  324.  
  325. static BOOL (*malloc_fail_handler)(unsigned size) = 0;
  326.  
  327. void set_malloc_fail_handler(BOOL (*handler)(unsigned))
  328. {
  329.     malloc_fail_handler = handler;
  330. }
  331.  
  332. BOOL malloc_fail(unsigned size)
  333. {
  334.     static in_fail_handler = 0;
  335.     if (malloc_fail_handler && (in_fail_handler == 0))
  336.     {
  337.         BOOL ret;
  338.         in_fail_handler++;
  339.         ret = (*malloc_fail_handler)(size);
  340.         in_fail_handler--;
  341.         return ret;
  342.     }
  343.     else
  344.         return TRUE;    // fail, don't retry
  345. }
  346.  
  347. /**********************************************************************/
  348.  
  349. winheap_stats()
  350. {
  351.     MEMHEAP _near *pheap;
  352.     int i;
  353.     unsigned num_live_heaps=0;
  354.     for (i=numheaps, pheap=memheap; i--; pheap++)
  355.         if (pheap->sel) num_live_heaps++;
  356.  
  357.     printf("Calls to _fmalloc:  %lu\n", num_fmalloc);
  358.     printf("Calls to try_alloc: %lu\n", num_try_allocs);
  359.     printf("Calls to _bmalloc:  %lu\n", num_bmallocs);
  360.     printf("Calls to _frealloc: %lu\n", num_frealloc);
  361.     printf("Calls to _ffree:    %lu\n", num_ffree);
  362.     printf("Calls to try_free:  %lu\n", num_try_frees);
  363.     printf("Get heap loops:     %lu\n", num_get_pheap_loops);
  364.     printf("Heaps:              %u\n", num_live_heaps);
  365.     printf("Freed heaps:        %u\n", numheaps - num_live_heaps);
  366. }
  367.  
  368. /**********************************************************************/
  369.  
  370. /* 0 as first argument to _bxxxx functions: use default data seg */
  371.  
  372. typedef void _near *NPTR;
  373.  
  374. NPTR _nmalloc(size_t size)                 { return _bmalloc(0, size); }
  375.  
  376. NPTR _ncalloc(unsigned num, unsigned size) { return _bcalloc(0, num, size); }
  377.  
  378. NPTR _nexpand(NPTR blk, size_t size)       { return _bexpand(0, blk, size); }
  379.  
  380. NPTR _nrealloc(NPTR blk, size_t size)      { return _brealloc(0, blk, size); }
  381.  
  382. void _nfree(NPTR memblock)                 { return _bfree(0, memblock); }
  383.  
  384. size_t _nmsize(NPTR memblock)              { return _bmsize(0, memblock); }
  385.  
  386. /**********************************************************************/
  387.  
  388. #if defined(M_I86SM) || defined(M_I86MM)    
  389. /* small or medium model */
  390. #define _FN(x)  _n ## x
  391. #else
  392. /* large or compact model */
  393. #define _FN(x)  _f ## x
  394. #endif
  395.  
  396. void *malloc(size_t size)             { return _FN(malloc(size)); }
  397.  
  398. void *calloc(size_t num, size_t size) { return _FN(calloc(num, size)); }
  399.  
  400. void *realloc(void *blk, size_t size) { return _FN(realloc(blk, size)); }
  401.  
  402. void *_expand(void *blk, size_t size) { return _FN(expand(blk, size)); }
  403.  
  404. void free(void *blk)                  { return _FN(free(blk)); }
  405.  
  406. size_t _msize(void *blk)              { return _FN(msize(blk)); }
  407.  
  408.